#ifndef __UTILS_SINGLETON_HH__
#define __UTILS_SINGLETON_HH__

namespace utils
{
#define SINGLETON(className) utils::Singleton<className>::instance()
#define RELEASE_SINGLETON(className) utils::Singleton<className>::release()

template <typename Type>
class Singleton
{
public:
    static Type* instance()
    {
        if (Singleton<Type>::_instance == nullptr)
            Singleton<Type>::_instance = new Type();
        return Singleton<Type>::_instance;
    }

    static void release()
    {
        delete Singleton<Type>::_instance;
    }

protected:
    Singleton() noexcept = default;
    Singleton(const Singleton<Type>& ) = delete;
    Singleton(Singleton<Type>&& ) = delete;
    Singleton<Type>& operator = (const Singleton<Type> &) = delete;
    Singleton<Type>& operator = (Singleton<Type>&&) = delete;
    ~Singleton() noexcept = default;

private:
    static Type* _instance;
};

template <typename Type>
Type* Singleton<Type>::_instance = nullptr;
}

#endif
